import subprocess
import ctypes
import sys
import os
import time

# 国内知名DNS服务器列表
DNS_PROVIDERS = {
    "1": {"name": "阿里云DNS", "primary": "223.5.5.5", "secondary": "223.6.6.6"},
    "2": {"name": "腾讯DNS", "primary": "119.29.29.29", "secondary": "182.254.116.116"},
    "3": {"name": "百度DNS", "primary": "180.76.76.76", "secondary": ""},
    "4": {"name": "114DNS", "primary": "114.114.114.114", "secondary": "114.114.115.115"},
    "5": {"name": "OneDNS", "primary": "117.50.11.11", "secondary": "117.50.22.22"},
    "6": {"name": "CNNIC DNS", "primary": "1.2.4.8", "secondary": "210.2.4.8"},
    "7": {"name": "Google DNS", "primary": "8.8.8.8", "secondary": "8.8.4.4"},
    "8": {"name": "Cloudflare DNS", "primary": "1.1.1.1", "secondary": "1.0.0.1"},
    "9": {"name": "OpenDNS", "primary": "208.67.222.222", "secondary": "208.67.220.220"},
    "0": {"name": "自定义DNS", "primary": "", "secondary": ""}
}

def is_admin():
    """Check if the script is running with administrator privileges."""
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

def run_as_admin():
    """Rerun the script with administrator privileges."""
    try:
        # 尝试以管理员身份重新运行脚本
        ret = ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
        if ret <= 32:  # ShellExecute返回值 <= 32 表示失败
            print("❌ 无法获取管理员权限。可能的原因：")
            print("   1. 用户取消了UAC提示")
            print("   2. 系统策略禁止提升权限")
            print("   3. 当前用户不在管理员组中")
            print("\n解决方案：")
            print("   1. 右键点击命令提示符，选择'以管理员身份运行'")
            print("   2. 然后在管理员命令提示符中运行此脚本")
            input("\n按任意键退出...")
            sys.exit(1)
        sys.exit()
    except Exception as e:
        print(f"❌ 获取管理员权限时发生错误: {e}")
        print("\n手动解决方案：")
        print("   1. 按Win+R，输入'cmd'")
        print("   2. 按Ctrl+Shift+Enter以管理员身份运行")
        print("   3. 在管理员命令提示符中重新运行此脚本")
        input("\n按任意键退出...")
        sys.exit(1)

def get_network_adapters():
    """Get a list of network adapters using PowerShell."""
    try:
        cmd = 'Get-NetAdapter | Where-Object {$_.Status -eq "Up" -and $_.InterfaceOperationalStatus -eq 1} | Select-Object -ExpandProperty InterfaceAlias'
        result = subprocess.run(['powershell', '-Command', cmd], capture_output=True, text=True, check=True)
        adapters = [a.strip() for a in result.stdout.split('\n') if a.strip()]
        return adapters
    except subprocess.CalledProcessError as e:
        print(f"❌ 获取网络适配器失败: {e}")
        print("可能的原因：")
        print("   1. PowerShell执行策略限制")
        print("   2. 系统权限不足")
        print("   3. 网络服务未启动")
        return []
    except Exception as e:
        print(f"❌ 意外错误: {e}")
        return []

def validate_ip(ip):
    """验证IP地址格式"""
    import re
    pattern = r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
    return re.match(pattern, ip) is not None

def display_dns_providers():
    """显示DNS服务器提供商列表"""
    print("\n🌐 DNS服务器选择:")
    print("=" * 50)
    for key, provider in DNS_PROVIDERS.items():
        if key == "0":
            print(f"   {key}. {provider['name']}")
        else:
            secondary = f", {provider['secondary']}" if provider['secondary'] else ""
            print(f"   {key}. {provider['name']}: {provider['primary']}{secondary}")
    print("=" * 50)

def test_dns_with_nslookup(dns_server, test_domain="www.baidu.com"):
    """使用nslookup测试DNS服务器响应"""
    try:
        print(f"\n🔍 使用DNS服务器 {dns_server} 测试域名解析...")
        print(f"测试域名: {test_domain}")
        
        # 使用nslookup测试DNS
        cmd = f'nslookup {test_domain} {dns_server}'
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)
        
        if result.returncode == 0:
            print("✅ DNS解析成功!")
            print("解析结果:")
            # 提取关键信息
            lines = result.stdout.split('\n')
            for line in lines:
                line = line.strip()
                if 'Address:' in line and dns_server not in line:
                    print(f"   IP地址: {line.split('Address:')[1].strip()}")
                elif 'Name:' in line:
                    print(f"   域名: {line.split('Name:')[1].strip()}")
            
            # 测试响应时间
            start_time = time.time()
            subprocess.run(f'ping -n 1 {dns_server}', shell=True, capture_output=True, timeout=5)
            response_time = (time.time() - start_time) * 1000
            print(f"   响应时间: {response_time:.0f}ms")
            return True
        else:
            print("❌ DNS解析失败")
            print("可能原因:")
            print("   1. DNS服务器无响应")
            print("   2. 网络连接问题")
            print("   3. DNS服务器地址错误")
            return False
            
    except subprocess.TimeoutExpired:
        print("⏰ DNS测试超时")
        print("可能原因: DNS服务器响应过慢或无法访问")
        return False
    except Exception as e:
        print(f"❌ DNS测试出错: {e}")
        return False

def get_dns_choice():
    """获取用户的DNS选择"""
    while True:
        display_dns_providers()
        choice = input("\n请选择DNS服务器 (输入数字0-9): ").strip()
        
        if choice in DNS_PROVIDERS:
            provider = DNS_PROVIDERS[choice]
            
            if choice == "0":  # 自定义DNS
                print(f"\n✅ 选择了: {provider['name']}")
                while True:
                    primary_dns = input("\n主DNS服务器: ").strip()
                    if primary_dns and validate_ip(primary_dns):
                        break
                    print("❌ 请输入有效的IPv4地址")
                
                secondary_dns = input("备用DNS服务器 (按回车跳过): ").strip()
                if secondary_dns and not validate_ip(secondary_dns):
                    print("⚠️  备用DNS地址无效，将忽略")
                    secondary_dns = ""
                
                return primary_dns, secondary_dns, "自定义DNS"
            else:
                print(f"\n✅ 选择了: {provider['name']}")
                return provider['primary'], provider['secondary'], provider['name']
        else:
            print("❌ 请输入有效的数字 (0-9)")

def dns_management_loop(selected_adapter):
    """DNS管理循环，包含测试和更换功能"""
    while True:
        # 获取DNS选择
        primary_dns, secondary_dns, provider_name = get_dns_choice()
        
        # 准备DNS服务器列表
        dns_servers = [primary_dns]
        if secondary_dns:
            dns_servers.append(secondary_dns)
        
        # 显示选择的DNS信息
        print(f"\n📝 选择的DNS设置 ({provider_name}):")
        for i, dns in enumerate(dns_servers, 1):
            print(f"   DNS服务器 {i}: {dns}")
        
        # 测试DNS服务器
        print(f"\n🧪 测试DNS服务器性能...")
        test_results = []
        for dns in dns_servers:
            result = test_dns_with_nslookup(dns)
            test_results.append(result)
        
        # 询问是否应用设置
        if any(test_results):
            apply_choice = input(f"\n是否应用此DNS设置到 '{selected_adapter}'? (y/N): ").strip().lower()
            if apply_choice in ['y', 'yes', '是']:
                success = set_dns(selected_adapter, dns_servers)
                if success:
                    print(f"\n🎉 DNS设置完成! 当前使用: {provider_name}")
                    
                    # 询问是否继续更换
                    continue_choice = input("\n是否要测试其他DNS或更换DNS? (y/N): ").strip().lower()
                    if continue_choice not in ['y', 'yes', '是']:
                        break
                else:
                    print("\n❌ DNS设置失败")
                    retry_choice = input("是否重试或选择其他DNS? (y/N): ").strip().lower()
                    if retry_choice not in ['y', 'yes', '是']:
                        break
            else:
                # 询问是否选择其他DNS
                other_choice = input("是否选择其他DNS? (y/N): ").strip().lower()
                if other_choice not in ['y', 'yes', '是']:
                    break
        else:
            print("⚠️  所有DNS服务器测试失败")
            retry_choice = input("是否选择其他DNS? (y/N): ").strip().lower()
            if retry_choice not in ['y', 'yes', '是']:
                break

def set_dns(adapter_name, dns_servers):
    """Set DNS servers for the specified network adapter."""
    try:
        # 验证DNS服务器IP地址
        for dns in dns_servers:
            if not validate_ip(dns):
                print(f"❌ 无效的IP地址: {dns}")
                print("请输入有效的IPv4地址格式 (例如: 8.8.8.8)")
                return False
        
        print(f"🔄 正在为 '{adapter_name}' 设置DNS服务器...")
        
        # 构建DNS服务器列表
        dns_list = ",".join([f'"{dns}"' for dns in dns_servers])
        cmd = f'Set-DnsClientServerAddress -InterfaceAlias "{adapter_name}" -ServerAddresses {dns_list} -ErrorAction Stop'
        
        result = subprocess.run(['powershell', '-Command', cmd], capture_output=True, text=True, check=True)
        
        print("✅ DNS设置成功!")
        for i, dns in enumerate(dns_servers, 1):
            print(f"   DNS服务器 {i}: {dns}")
        
        # 验证更改
        print("\n🔍 验证DNS设置...")
        cmd = f'Get-DnsClientServerAddress -InterfaceAlias "{adapter_name}" -AddressFamily IPv4 | Select-Object -ExpandProperty ServerAddresses'
        result = subprocess.run(['powershell', '-Command', cmd], capture_output=True, text=True, check=True)
        
        current_dns = [dns.strip() for dns in result.stdout.split('\n') if dns.strip()]
        if current_dns:
            print("当前DNS设置:")
            for i, dns in enumerate(current_dns, 1):
                print(f"   DNS服务器 {i}: {dns}")
        else:
            print("⚠️  无法获取当前DNS设置")
        
        return True
        
    except subprocess.CalledProcessError as e:
        print(f"❌ 设置DNS失败: {e}")
        if "Access is denied" in str(e):
            print("错误原因: 权限不足")
            print("解决方案: 请确保以管理员身份运行此脚本")
        elif "InterfaceAlias" in str(e):
            print("错误原因: 网络适配器名称无效")
            print("解决方案: 请重新选择正确的网络适配器")
        else:
            print("可能的原因:")
            print("   1. 网络适配器不存在或已禁用")
            print("   2. DNS服务器地址无效")
            print("   3. 系统网络服务异常")
        return False
    except Exception as e:
        print(f"❌ 意外错误: {e}")
        return False

if __name__ == "__main__":
    print("🔧 Windows DNS设置工具")
    print("=" * 40)
    
    # 检查管理员权限
    if not is_admin():
        print("⚠️  此脚本需要管理员权限来修改网络设置")
        print("正在尝试获取管理员权限...")
        run_as_admin()
    
    print("✅ 已获得管理员权限")
    
    # 获取网络适配器
    print("\n🔍 正在扫描活动的网络适配器...")
    adapters = get_network_adapters()
    
    if not adapters:
        print("❌ 未找到活动的网络适配器")
        print("请检查：")
        print("   1. 网络连接是否正常")
        print("   2. 网络适配器是否已启用")
        print("   3. 网络服务是否正常运行")
        input("\n按任意键退出...")
        sys.exit(1)
    
    print(f"✅ 找到 {len(adapters)} 个活动的网络适配器")
    print("\n📋 可用的网络适配器:")
    for i, adapter in enumerate(adapters, 1):
        print(f"   {i}. {adapter}")
    
    try:
        while True:
            choice_input = input(f"\n请选择适配器编号 (1-{len(adapters)}): ").strip()
            try:
                choice = int(choice_input) - 1
                if 0 <= choice < len(adapters):
                    break
                else:
                    print(f"❌ 请输入 1 到 {len(adapters)} 之间的数字")
            except ValueError:
                print("❌ 请输入有效的数字")
        
        selected_adapter = adapters[choice]
        print(f"\n✅ 已选择适配器: {selected_adapter}")
        
        # 进入DNS管理循环
        dns_management_loop(selected_adapter)
            
    except KeyboardInterrupt:
        print("\n\n❌ 用户中断操作")
    except Exception as e:
        print(f"\n❌ 程序异常: {e}")
    
    input("\n按任意键退出...")
